functor X86AsmizeRa (S : X86ASMIZERA_STRUCTS) : X86ASMIZERA =
struct
  open S
  
  structure X86Asm = X86Asm
  structure Machine = Machine
  
  val error = ErrorMsg.error
  
  val tag = false
  fun debugPrint s =
      if tag
      then print s
      else ()      
  
  local open X86Asm
  in structure XC = Cmd
     structure XL = Location
     structure XR = Register
     structure XO = Operand
     structure XI = Ins
     structure XK = Block
     structure XF = Function
     structure XP = Program
  end
  
  local open Machine
  in structure L = Location
     structure B = Binop
     structure R = Register
     structure O = Operand
     structure K = Block
     structure S = Structs
     structure J = Transfer
     structure M = Stm
     structure F = Function
     structure P = Program
     structure Intl = Intl
     structure Id = Id
     structure T = Types
  end
  
  fun printList (n, l, info) =
      let val _ = debugPrint (String.concat ["\nthe ", info, " of ", Id.toString n, " is:\n"])
          val _ = List.app debugPrint (List.map Id.toString l)
      in  ()
      end


  val {get = location, set = setLocation, destroy = destroyLocation, ...} :
      {get : Id.t -> XL.t, set : Id.t * XL.t -> unit, destroy : unit -> unit} =
      Property.destGetSetOnce (Id.plist, Property.initConst XL.Global)
      
  fun destroy () = destroyLocation ()

  fun transReg r =
      case r
       of R.eax => XR.eax
        | R.ebx => XR.ebx
        | R.ecx => XR.ecx
        | R.edx => XR.edx
        | R.esi => XR.esi
        | R.edi => XR.edi
        | R.ebp => XR.ebp
        | R.esp => XR.esp
        
  fun transLocation l =
      case l
       of L.InStack i => XL.InStack i
        | L.InReg r => XL.InReg (transReg r)      
        | L.Global => XL.Global
        | L.NoWhere => raise Fail "compiler bug"
(*  
  fun isReg id = 
      case (location id)
       of XL.InReg r => true
        | _ => false
        
  fun isStack id =
      case (location id)
       of XL.InStack i => true
        | _ => false
*)  
  fun isMem oper =
      case oper
       of XO.Rmem _ => true
        | _ => false 
  
  fun transOperand v = 
      case v
       of O.OpVoid => 
          {stms = [], oper = XO.OpVoid}
        | O.IntNum i => 
          {stms = [], oper = XO.IntNum i}
        | O.Var {id, ty} =>
          let val idLoc = location id
          in  case idLoc
               of XL.Global => raise Fail "not yet!"
                | XL.InStack i => 
                  {stms = [],
                   oper = XO.Rmem {reg = XR.ebp, off = i, ty = ty}}
                | XL.InReg r => 
                  {stms = [],
                   oper = XO.Reg {reg = r, ty = ty}}
          end
        | O.True => 
          {stms = [], oper = XO.True}
        | O.False => 
          {stms = [], oper = XO.False}
        | O.Null => 
          {stms = [], oper = XO.Null}
        | O.Mem {id, ty} => 
          let val idLoc = location id
          in  case idLoc
               of XL.Global => raise Fail "not yet "
                | XL.InStack i => 
                  {stms = [XI.I {cmd = XC.Mov,
                                 dest = XO.Reg {reg = XR.ebx, ty = T.Pointt ty},
                                 src = XO.Rmem {reg = XR.ebp, off = i, ty = T.Pointt ty}}],
                   oper = XO.Rmem {reg = XR.ebx, off = Intl.fromInt 0, ty = ty}}
                | XL.InReg r => 
                  {stms = [],
                   oper = XO.Rmem {reg = r, off = Intl.fromInt 0, ty = ty}}
               
          end
        | O.Reg {reg, ty} => 
          {stms = [], oper = XO.Reg {reg = transReg reg, ty = ty}}
      

  fun transStm s = 
      let val _ = ()
      in  case s
           of M.Assign {line, dest, src, ty} =>
              let val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val {stms = getSrc, oper = newSrc} = transOperand src
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val srcToDest = XI.I {cmd = XC.Mov, src = newSrc, dest = newDest}
                  val srcToEax = XI.I {cmd = XC.Mov, src = newSrc, dest = Eax} 
              in  case (newDest, newSrc)
                   of (XO.Rmem _, XO.Rmem _) =>
                      getSrc @
                      [srcToEax] @
                      getDest @
                      [eaxToDest]
                    | _ =>
                      getSrc @ getDest @
                      [srcToDest]    
              end
            | M.AssignExp {line, dest, bop = B.Plus, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val addSrc2Eax = XI.I {cmd = XC.Add, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val src1ToDest = XI.I {cmd = XC.Mov, src = newSrc1, dest = newDest}
                  val addSrc2Dest = XI.I {cmd = XC.Add, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      let val _ = ()
                      in  if (isMem newSrc1) orelse (isMem newSrc2)
                          then getSrc1 @ 
                               [src1ToEax] @
                               getSrc2 @
                               [addSrc2Eax] @
                               getDest @
                               [eaxToDest]
                          else getDest @
                               [src1ToDest, 
                                addSrc2Dest]
                      end
                    | XO.Reg _ =>
                      getSrc1 @
                      [src1ToDest] @
                      getSrc2 @
                      [addSrc2Dest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Minus, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val subSrc2Eax = XI.I {cmd = XC.Sub, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val src1ToDest = XI.I {cmd = XC.Mov, src = newSrc1, dest = newDest}
                  val subSrc2Dest = XI.I {cmd = XC.Sub, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      let val _ = ()
                      in  if (isMem newSrc1) orelse (isMem newSrc2)
                          then getSrc1 @ 
                               [src1ToEax] @
                               getSrc2 @
                               [subSrc2Eax] @
                               getDest @
                               [eaxToDest] 
                          else getDest @
                               [src1ToDest, 
                                subSrc2Dest]
                      end
                    | XO.Reg _ =>
                      getSrc1 @
                      [src1ToDest] @
                      getSrc2 @
                      [subSrc2Dest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Times, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Mul, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val src1ToDest = XI.I {cmd = XC.Mov, src = newSrc1, dest = newDest}
                  val opSrc2Dest = XI.I {cmd = XC.Mul, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      let val _ = ()
                      in  if (isMem newSrc1) orelse (isMem newSrc2)
                          then getSrc1 @ 
                               [src1ToEax] @
                               getSrc2 @
                               [opSrc2Eax] @
                               getDest @
                               [eaxToDest]
                          else getDest @
                               [src1ToDest, 
                                opSrc2Dest]
                      end
                    | XO.Reg _ =>
                      getSrc1 @
                      [src1ToDest] @
                      getSrc2 @
                      [opSrc2Dest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.And, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.And, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val src1ToDest = XI.I {cmd = XC.Mov, src = newSrc1, dest = newDest}
                  val opSrc2Dest = XI.I {cmd = XC.And, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      let val _ = ()
                      in  if (isMem newSrc1) orelse (isMem newSrc2)
                          then getSrc1 @ 
                               [src1ToEax] @
                               getSrc2 @
                               [opSrc2Eax] @
                               getDest @
                               [eaxToDest]
                          else getDest @
                               [src1ToDest, 
                                opSrc2Dest]
                      end
                    | XO.Reg _ =>
                      getSrc1 @
                      [src1ToDest] @
                      getSrc2 @
                      [opSrc2Dest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Or, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Or, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val src1ToDest = XI.I {cmd = XC.Mov, src = newSrc1, dest = newDest}
                  val opSrc2Dest = XI.I {cmd = XC.Or, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      let val _ = ()
                      in  if (isMem newSrc1) orelse (isMem newSrc2)
                          then getSrc1 @ 
                               [src1ToEax] @
                               getSrc2 @
                               [opSrc2Eax] @
                               getDest @
                               [eaxToDest]
                          else getDest @
                               [src1ToDest, 
                                opSrc2Dest]
                      end
                    | XO.Reg _ =>
                      getSrc1 @
                      [src1ToDest] @
                      getSrc2 @
                      [opSrc2Dest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Not, src, ty} =>
              let val src = List.hd src
                  val {stms = getSrc, oper = newSrc} = transOperand src
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val srcToEax = XI.I {cmd = XC.Mov, src = newSrc, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val xorEax = XI.I {cmd = XC.Xor, src = XO.IntNum (Intl.fromInt (~1)), dest = Eax}
                  val seteEax = XI.I {cmd = XC.Sete, src = Eax, dest = XO.OpVoid}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc @
                      [srcToEax, xorEax, seteEax] @ 
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc @
                      [srcToEax, xorEax, seteEax] @ 
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Divide, src, ty} => raise Fail "to do"  
            | M.AssignExp {line, dest, bop = B.Modus, src, ty} => raise Fail "to do"    
(*
            | M.AssignExp {line, dest, bop = B.Divide, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Mul, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val opSrc2Dest = XI.I {cmd = XC.Mul, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ => 
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Modus, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Mul, src = newSrc2, dest = Eax}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
                  val opSrc2Dest = XI.I {cmd = XC.Mul, src = newSrc2, dest = newDest}
              in  case newDest
                   of XO.Rmem _ => 
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
*)
            | M.AssignExp {line, dest, bop = B.Eq, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Cmp, src = newSrc2, dest = Eax}
                  val seteEax = XI.I {cmd = XC.Sete, src = Eax, dest = XO.OpVoid}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, seteEax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, seteEax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Ne, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Cmp, src = newSrc2, dest = Eax}
                  val setneEax = XI.I {cmd = XC.Setne, src = Eax, dest = XO.OpVoid}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setneEax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setneEax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Gt, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Cmp, src = newSrc2, dest = Eax}
                  val setgEax = XI.I {cmd = XC.Setg, src = Eax, dest = XO.OpVoid}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setgEax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setgEax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Ge, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Cmp, src = newSrc2, dest = Eax}
                  val setgeEax = XI.I {cmd = XC.Setge, src = Eax, dest = XO.OpVoid}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setgeEax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setgeEax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Lt, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Cmp, src = newSrc2, dest = Eax}
                  val setlEax = XI.I {cmd = XC.Setl, src = Eax, dest = XO.OpVoid}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setlEax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setlEax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.AssignExp {line, dest, bop = B.Le, src, ty} =>
              let val src1 = List.hd src
                  val {stms = getSrc1, oper = newSrc1} = transOperand src1
                  val src2 = case (List.tl src)
                              of [] => raise Fail "Compiler bug: Invalid srcs"
                               | x :: xs => x
                  val {stms = getSrc2, oper = newSrc2} = transOperand src2
                  val {stms = getDest, oper = newDest} = transOperand dest
                  val Eax = XO.Reg {reg = XR.eax, ty = ty}
                  val src1ToEax = XI.I {cmd = XC.Mov, src = newSrc1, dest = Eax}
                  val opSrc2Eax = XI.I {cmd = XC.Cmp, src = newSrc2, dest = Eax}
                  val setleEax = XI.I {cmd = XC.Setle, src = Eax, dest = XO.OpVoid}
                  val eaxToDest = XI.I {cmd = XC.Mov, src = Eax, dest = newDest}
              in  case newDest
                   of XO.Rmem _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setleEax] @
                      getDest @
                      [eaxToDest]
                    | XO.Reg _ =>
                      getSrc1 @ 
                      [src1ToEax] @
                      getSrc2 @
                      [opSrc2Eax, setleEax] @
                      getDest @
                      [eaxToDest]
                    | _ => raise Fail "Compiler bug: Invalid dest"
              end
            | M.Call {line, fid, src, ty} =>
              let val newSrc = List.rev src
                  fun ArgToPush s =
                     let val {stms = getS, oper = newA} = transOperand s
                         val pushS = XI.I {cmd = XC.Push, src = newA, dest = XO.OpVoid}
                     in  getS @
                         [pushS]
                     end
                  val push = List.concat (List.map ArgToPush newSrc)
                  val sizeSrc = (List.length src) * 4
                  val Esp = XO.Reg {reg = XR.esp, ty = T.Voidt}
                  val push = push @ 
                             [XI.I {cmd = XC.Call, src = XO.Label {id = fid, ty = ty}, dest = XO.OpVoid},
                              XI.I {cmd = XC.Add, src = XO.IntNum (Intl.fromInt sizeSrc), dest = Esp}]
              in  push
              end  
            | M.Alloc {line, fid, ty} =>
              let val size = Intl.fromInt ((T.size ty) * 4)
                  val push = XI.I {cmd = XC.Push, src = XO.IntNum size, dest = XO.OpVoid}
                  val push = push :: [XI.I {cmd = XC.Call, src = XO.Label {id = fid, ty = T.Pointt ty}, dest = XO.OpVoid}]
                  val Esp = XO.Reg {reg = XR.esp, ty = T.Voidt}
                  val push = push @ [XI.I {cmd = XC.Add, src = XO.IntNum (Intl.fromInt 4), dest = Esp}]
              in  push
              end
           
                            
      end                  
                               
          
  fun transTransfer (j, exit, rettype) = 
      case j
       of J.Jump {line, label} => [XI.I {cmd = XC.Jmp, src = XO.Label {id = label, ty = T.Voidt}, dest = XO.OpVoid}]
        | J.If {line, value, truee, falsee} =>
          let val {stms = newStms, oper = newValue} = transOperand value
          in newStms @
             [XI.I {cmd = XC.Cmp, src = XO.IntNum (Intl.fromInt 0), dest = newValue},
              XI.I {cmd = XC.Jne, src = XO.Label {id = truee, ty = T.Voidt}, dest = XO.OpVoid},
              XI.I {cmd = XC.Jmp, src = XO.Label {id = falsee, ty = T.Voidt}, dest = XO.OpVoid}]
          end
        | J.Return {line, value = O.OpVoid} => []
        | J.Return {line, value} =>
          let val {stms, oper} = transOperand value
          in  stms @ [XI.I {cmd = XC.Mov, src = oper, dest = XO.Reg {reg = XR.eax, ty = rettype}}]
          end 
  
  fun transStms (stms, transfer, exit, rettype) = 
      let val ins1 = List.concat (List.map transStm stms)
          val ins2 = transTransfer (transfer, exit, rettype)
          val ins = ins1 @ ins2
      in  ins
      end
  
  fun transBlock (b, exit, rettype) =
      case b
       of K.T {name, prop, stms, transfer, successors} =>
          let val newIns = transStms (stms, transfer, exit, rettype)
              val newSucc = successors
              val new = XK.T {name = name,
                              prop = prop,
                              ins = newIns,
                              successors = newSucc}
          in  new
          end
  
  fun transBlocks (bs, exit, rettype) =
      List.map (fn b => transBlock (b, exit, rettype)) bs
    
  fun setLocalsLocation l =
      let fun doit all =
              case all
               of [] => ()
                | {id, ty, loc} :: xs => 
                  let val loc = transLocation loc
                      val _ = setLocation (id, loc)                      
                  in  doit xs
                  end
          val _ = doit l
      in  ()
      end
      
  fun setArgsLocation l =
      let fun doit l =
              case l
               of [] => ()
                | {id, loc, ty} :: xs =>
                  let val loc = transLocation loc
                      val _ = setLocation (id, loc)
                  in  doit xs
                  end
          val _ = doit l
      in  ()
      end    
      
  fun addPrologEpilog (blocks, start, exit, prolog, epilog) =
      case blocks
       of [] => []
        | x :: xs => 
          if Id.equals (XK.name x, start)
          then XK.addInsHead (x, prolog) :: addPrologEpilog (xs, start, exit, prolog, epilog)   
          else if Id.equals (XK.name x, exit)
               then XK.addInsTail (x, epilog) :: addPrologEpilog (xs, start, exit, prolog, epilog)
               else x :: addPrologEpilog (xs, start, exit, prolog, epilog)       
   
  fun transFunc f = 
      case f
       of F.T {name, exit, rettype, args, locals, stackSize, blocks, pre, post} =>
          let val _ = setLocalsLocation locals
              val _ = setArgsLocation args
              val newBlocks = transBlocks (blocks, exit, rettype)
              val prolog = [XI.I {cmd = XC.Prolog, src = XO.IntNum stackSize, dest = XO.OpVoid}]
              val epilog = [XI.I {cmd = XC.Epilog, src = XO.IntNum stackSize, dest = XO.OpVoid}]
              val newBlocks = addPrologEpilog (newBlocks, name, exit, prolog, epilog)
              val new = XF.T {name = name,
                              exit = exit,
                              rettype = rettype,
                              args = List.map (fn {id, loc, ty} => {id = id, ty = ty}) args,
                              locals = List.map (fn {id, loc, ty} => {id = id, ty = ty}) locals,
                              blocks = newBlocks,
                              pre = XO.True,
                              post = XO.True}
              val _ = destroy ()
          in  new
          end
                
  fun transProg p =
      case p
       of P.T {structs,
               gvars,
               funcs} =>
          let val new = XP.T {structs = [],
                              gvars = gvars,
                              funcs = List.map transFunc funcs}
          in  new
          end
  

  fun trans p = 
      let val _ = debugPrint "ra to x86 assembly code translation starting\n"
          val new = transProg p
          val _ = debugPrint "ra to x86 assembly code translation finished\n"
      in  new
      end
end
